package com.wg.core.properties;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.hutool.setting.dialect.Props;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 属性加载器
 *
 * @author 少爷123
 */
public class PropertiesLoader {
    private static final Log log = LogFactory.get(PropertiesLoader.class);
    private static final String DEFAULT_PROPERTIES = "application.properties";
    private static final String PROFILE_PREFIX = "application-";
    private static final String PROFILE_SUFFIX = ".properties";
    private static final String PROFILES_ACTIVE = "profiles.active";
    private static final String ARG_PREFIX = "--";

    /**
     * 加载并合并所有配置源
     *
     * @param args 命令行参数
     * @return 合并后的配置Map
     */
    public Map<String, String> loadProperties(String... args) {
        // 1. 解析命令行参数
        final Map<String, String> commandLineArgs = parseCommandLineArgs(args);

        // 2. 确定激活的配置文件
        final String profile = commandLineArgs.getOrDefault(PROFILES_ACTIVE, null);

        // 3. 加载文件配置（默认配置 + profile配置）
        final Map<String, String> fileConfigs = loadFileConfigurations(profile);

        // 4. 合并配置（命令行参数优先级最高）
        return mergeConfigurations(fileConfigs, commandLineArgs);
    }

    /**
     * 解析命令行参数（格式：--key=value）
     *
     * @param args 命令行参数数组
     * @return 解析后的键值对Map
     */
    private Map<String, String> parseCommandLineArgs(String[] args) {
        if (args == null || args.length == 0) {
            return Collections.emptyMap();
        }

        final Map<String, String> parsedArgs = new HashMap<>(args.length);
        for (String arg : args) {
            if (arg.startsWith(ARG_PREFIX)) {
                final String argContent = arg.substring(ARG_PREFIX.length());
                final int splitIndex = argContent.indexOf('=');

                if (splitIndex > 0) {
                    final String key = argContent.substring(0, splitIndex).trim();
                    final String value = argContent.substring(splitIndex + 1).trim();
                    if (!key.isEmpty() && !value.isEmpty()) {
                        parsedArgs.put(key, value);
                    }
                } else {
                    log.warn("Invalid command-line argument format: '{}'", arg);
                }
            }
        }
        return parsedArgs;
    }

    /**
     * 加载文件配置（默认配置 + 激活的profile配置）
     *
     * @param activeProfile 激活的profile名称
     * @return 合并后的文件配置
     */
    private Map<String, String> loadFileConfigurations(String activeProfile) {
        final Map<String, String> configs = new HashMap<>(64);

        // 1. 加载默认配置
        loadConfigFile(DEFAULT_PROPERTIES, configs);

        // 2. 确定最终启用的profile
        final String effectiveProfile = resolveActiveProfile(activeProfile, configs);

        // 3. 加载profile专用配置
        if (StrUtil.isNotBlank(effectiveProfile)) {
            final String profileFileName = PROFILE_PREFIX + effectiveProfile + PROFILE_SUFFIX;
            loadConfigFile(profileFileName, configs);
        }
        return configs;
    }

    /**
     * 确定有效的profile名称
     *
     * @param specifiedProfile 命令行指定的profile
     * @param configs          当前加载的配置
     * @return 最终生效的profile名称
     */
    private String resolveActiveProfile(String specifiedProfile, Map<String, String> configs) {
        // 优先使用命令行参数中的profile
        if (StrUtil.isNotBlank(specifiedProfile)) {
            return specifiedProfile;
        }

        // 其次使用默认配置中声明的profile
        final String configProfile = configs.get(PROFILES_ACTIVE);
        if (StrUtil.isNotBlank(configProfile)) {
            log.info("Using profile from default config: {}", configProfile);
            return configProfile;
        }

        log.warn("No active profile specified. Using default configuration only.");
        return null;
    }

    /**
     * 加载单个配置文件
     *
     * @param fileName 配置文件名
     * @param target   目标配置Map
     */
    private void loadConfigFile(String fileName, Map<String, String> target) {
        if (!FileUtil.exist(fileName)) {
            log.error("Configuration file not found: [{}]", fileName);
            return;
        }

        final Props props = new Props(fileName);
        for (Map.Entry<Object, Object> entry : props.entrySet()) {
            final String key = Objects.toString(entry.getKey(), "").trim();
            final String value = Objects.toString(entry.getValue(), "").trim();

            if (!key.isEmpty()) {
                if (target.containsKey(key)) {
                    log.warn("Overwriting configuration: [{}] (old: '{}', new: '{}')",
                            key, target.get(key), value);
                }
                target.put(key, value);
            }
        }
    }

    /**
     * 合并配置（文件配置 + 命令行参数）
     *
     * @param fileConfigs 文件配置
     * @param cmdArgs     命令行参数
     * @return 合并后的最终配置
     */
    private Map<String, String> mergeConfigurations(Map<String, String> fileConfigs,
                                                    Map<String, String> cmdArgs) {
        final Map<String, String> finalConfig = new HashMap<>(fileConfigs);
        cmdArgs.forEach((key, value) -> {
            if (finalConfig.containsKey(key)) {
                log.info("Overriding configuration from command-line: [{}]={}", key, value);
            }
            finalConfig.put(key, value);
        });
        return finalConfig;
    }
}